package com.lsk.netdisk.gateway.helper;

import com.lsk.netdisk.common.redis.core.RedisComponent;
import com.lsk.netdisk.common.response.core.ResponseParser;
import com.lsk.netdisk.common.response.exception.HttpException;
import com.lsk.netdisk.gateway.mapper.CookieMapper;
import com.lsk.netdisk.gateway.mapper.ParamMapper;
import com.lsk.netdisk.gateway.mapper.RespCookieMapper;
import com.lsk.netdisk.gateway.mapper.URLsMapper;
import com.lsk.netdisk.gateway.models.*;
import com.lsk.netdisk.gateway.util.WebUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;

@Slf4j
@Component
public class RequestHelper {
	@Autowired
	private RestTemplate restTemplate;
	@Autowired
	private URLsMapper urlMapper;
	@Autowired
	private ParamMapper paramMapper;
	@Autowired
	private CookieMapper cookieMapper;
	@Autowired
	private LoadBalancerClient loadBalancerClient;
	@Autowired
	private RedisComponent redisComponent;
	@Autowired
	private RespCookieMapper respCookieMapper;

	private Random random = new Random();

	public Response handleAuth(HttpServletRequest req){
		String path = req.getServletPath().replace("/auth","");
		if (!checkPermission(path, WebUtil.getCookieValue(req.getCookies(),"token"))){
			throw new HttpException("Forbidden",403);
		}
		log.info(path);
		URL url = urlMapper.queryURLByPath(path);
		if(url == null){
			throw new HttpException("Not Found",404);
		}
		Integer urlID = url.getId();
		List<Param> params = paramMapper.queryParamsByUrlID(urlID);
		Map<String,String> paramMap = new HashMap<>();
		for(Param param : params){
			String name = param.getName();
			String value = req.getParameter(name);
			log.info(name+":"+value);
			paramMap.put(name,value);
		}
		String reqTokenUUID = UUID.randomUUID().toString();
		String reqID = UUID.randomUUID().toString();
		String reqToken = reqID+":"+reqTokenUUID;
		redisComponent.set(reqID+"-TOKEN",reqToken,100000);
		paramMap.put("reqToken",reqToken);
		Map<String,String> cookieMap = new HashMap<>();
		List<Cookie> cookies = cookieMapper.queryCookiesByURLID(urlID);
		for(Cookie cookie : cookies){
			String name = cookie.getName();
			String value = getCookieValue(req,name);
			cookieMap.put(name,value);
		}
		ServiceInstance serviceInstance = loadBalancerClient.choose("auth");
		String address = "http://"+serviceInstance.getHost()+":"+serviceInstance.getPort()+path;
		log.info(address);
		HttpMethod method = HttpMethod.valueOf(req.getMethod());
		ResponseEntity resp = sendRequest(method,address,paramMap,cookieMap);
		Response response = new Response();
		List<String> responseCookies = resp.getHeaders().get(HttpHeaders.COOKIE);
		List<RespCookie> respCookies = respCookieMapper.queryRespCookieByURLID(urlID);
		Map<String,String> responseCookiesProcessed = processCookies(responseCookies);
		for (RespCookie respCookie : respCookies){
			String name = respCookie.getName();
			log.info(name);
		}
		response.setRespData(resp.getBody());
		return response;
	}
	private ResponseEntity<Object> sendRequest(HttpMethod method,String url, Map<String,String> params, Map<String,String> cookies){
		List<String> cookieList = new ArrayList<>();
		for(Map.Entry<String,String> entry : cookies.entrySet()){
			String name = entry.getKey();
			String value = entry.getValue();
			cookieList.add(name+"="+value);
		}
		HttpHeaders httpHeaders = new HttpHeaders();
		if(cookieList.size() > 0){
			httpHeaders.put("Cookie",cookieList);
		}
		MultiValueMap<String,String> requestParams = new LinkedMultiValueMap<>();
		for(Map.Entry<String,String> entry:params.entrySet()){
			String name = entry.getKey();
			String value = entry.getValue();
			requestParams.add(name,value);
		}
		HttpEntity<MultiValueMap<String,String>> httpEntity = new HttpEntity<>(requestParams,httpHeaders);
//		return restTemplate.exchange(url,method,httpEntity,Object.class);
		ResponseEntity<Object> responseEntity = restTemplate.exchange(url,method,httpEntity,Object.class);
		return responseEntity;
	}
	private String getCookieValue(HttpServletRequest req, String name){
		javax.servlet.http.Cookie[] cookies = req.getCookies();
		for (javax.servlet.http.Cookie cookie : cookies){
			if (cookie.getName().equals(name)){
				return cookie.getValue();
			}
		}
		throw new RuntimeException("Cookie not found!");
	}
	private Map<String,String> processCookies(List<String> src){
		if(src == null){
			return null;
		}
		Map<String,String> result = new HashMap<>();
		for (String cookie : src){
			log.info(cookie);
		}
		return result;
	}
	private String getURL(String service, String api){
		ServiceInstance serviceInstance = loadBalancerClient.choose(service);
		String host = serviceInstance.getHost();
		String port = Integer.toString(serviceInstance.getPort());
		return "http://"+host+":"+port+"/"+api;
	}
	private boolean checkPermission(String url, String token){
		String checkURL = getURL("auth","/hasPermission");
		Map<String,String> params = new HashMap<>();
		log.info(url);
		params.put("url",url);
		Map<String,String> cookies = new HashMap<>();
		cookies.put("token",token);
		ResponseEntity<Object> responseEntity = sendRequest(HttpMethod.POST,checkURL,params,cookies);
		return (Boolean)((LinkedHashMap)((LinkedHashMap)responseEntity.getBody())).get("data");
	}
}
